#ifndef AREA__
#define AREA__

#include <cmath>
#include <algorithm>
#include <iomanip>

#include "area_cell.h"
#include "options.h"
#include "base.h"

/** Abstraktni zakladni trida reprezentujici mapu (zadani problemu FAP).
 * Slouzi jako zaklad pro tvorbu vsech map, obsahuje virtualni metody, 
 * ktere je nutne v konkretnich mapach predefinovat (jako napriklad setAntenaPositions()
 * pro nastaveni pozic jednotlivych anten).
 * Poskytuje metody pro praci s prirazenim frekvenci (to si pamatuje a umoznuje jej napriklad
 * ukladat do historie a opet nacitat), pocita matici ruseni atd.
 */
class Area {
public:
	Area(Options * o);
	Area(Options * o, int cells_cnt);
	virtual ~Area();
	int frequencyDistance(int i, int j);
	void printFrequencyDistances();
	void printConstraints();
	virtual int getMaxFrequencies();
	void initialize(int size); // should be only called after the size and demands has been set
	void setFrequencyCount(int f);
	void setCellCount(int cell_cnt);
	void readDemands(int * demands = NULL);
	virtual void save();
	virtual void load();
	virtual void clear();
	bool checkChange(int call, int freq, int cell = -1);
	int isAssignmentCorrect(int max);
	bool assignCall(int call, int freq, int cell = -1);
	bool assignCell(int cell, int freq);
	int findCell(int call);
	void findCell(int call, int &cell);
	/** Vrati informace o nastaveni mapy.
	 */
	virtual std::string getDetail() {
		return "";
	}
	void sort(); // provede setrideni pridelenych frekvenci - je jasne videt, ktere jsou pridelene a ktere ne
	int * sortedCalls();
	int * calls, ///< pole frekvenci prirazenych jednotlivym vysilacum (zde je ulozeno vysledne prirazeni frekvenci)
		* calls_saved, ///< ulozene pole prirazenych frekvenci
		* calls_owner; ///< prislusnost vysilacu k jednotlivym antenam
	int * cell_min, ///< pole nejmensich volnych frekvenci pro jednotlive anteny (vsechny nizsi frekvence jsou pro danou antenu zakazany)
		* cell_min_saved; ///< ulozene pole nejmensich volnych frekvenci
	Cell * cells; ///< pole vsech anten na mape
	int * freq_dist; ///< matice vzdalenosti mezi jednotlivymi antenami, vzdalenost mezi antenami i a j je na pozici 'CELLS_PHI * i + j'
	bool * freq_avail, ///< bitova maska pridelitelnych frekvenci pro vsechny anteny, frekvence f a antena i na pozici 'i * frequencies + f'
		* freq_avail_saved; ///< ulozena bitova maska freq_avail
	int size, ///< pocet vysilacu
		CELLS_CNT; ///< pocet anten
	int frequencies; ///< maximalni pocet frekvenci, se kterym je mapa schopna operovat (urcuje velikost internich struktur)
	double * reuse_distances; ///< vektor znovupouzitelnych vzdalenosti
	int reuse_size; ///< pocet hodnot ve vektoru znovupouzitelnych vzdalenosti
protected:
	void countDistances(double * r = 0, int r_size = 0);
private:
	Options * general; ///< zakladni nastaveni mapy
	/* Virtualni funkce, ktera ma za ukol nastavit pozice vsech anten na mape.
	 */
	virtual void setAntenaPositions() = 0;
	void setFrequencyDistance(int i, int j, int d);
	int * calls_sorted; ///< prirazeni frekvenci, frekvence jsou v nem pro kazdou antenu setrideny podle velikosti
};

#endif
